#include <string>
#include <vector>
#include "log.hpp"
#include "redis.h"

Redis* Redis::m_instance = NULL;
redisContext* Redis::m_ctx= NULL;
vector<pair<string,unsigned int> > Redis::m_vServers;

using namespace std;

Redis *Redis::instance()
{
    if (!m_instance)
        m_instance = new Redis();

    return m_instance;
}

void Redis::release()
{
    if (!m_instance)
    {
        delete m_instance;
        m_instance = NULL;
        redisFree(m_ctx);
        m_ctx = NULL;
    }
}

void Redis::SetServer(const string &ip, unsigned int port) 
{
    if (m_instance == NULL)
        m_instance = new Redis();

    m_vServers.push_back(pair<string,unsigned int>(ip,port));
}


bool Redis::Reconnect()
{
    vector<pair<string,unsigned int> >::iterator it = m_vServers.begin();
    while (it != m_vServers.end())
    {
        if (m_ctx != NULL)
            redisFree(m_ctx);
        
        DBG_LOG("connecting to %s:%u.",it->first.c_str(),it->second);
        m_ctx = redisConnect(it->first.c_str(), it->second);
        if (m_ctx == NULL || m_ctx->err )
        {
            ++it;
            continue;
        }
        break;
    }

    if (m_ctx == NULL || m_ctx->err )
    {
        ERR_LOG("Failed to connect redis server.");
        return false;
    }
    return true;
}

void Redis::Exec(const string& cmd)
{
    // 初始化
    if (m_ctx == NULL)
    {
        instance()->Reconnect();
    }
    // 初始化成功 or 失败
    if (m_ctx == NULL)
    {
        ERR_LOG("No Available redis server.");
        return;
    }
    redisReply* rsp = (redisReply*)redisCommand(m_ctx,cmd.c_str());
    // m_ctx->err 检测连接中断 或者 server 挂掉
    while (m_ctx->err != 0)
    {
        bool bConnectOk = instance()->Reconnect();
        if (bConnectOk)
        {
            rsp = (redisReply*)redisCommand(m_ctx,cmd.c_str());
            break;
        }
        else
        {
            ERR_LOG("send command error:%s.",rsp==NULL?"":rsp->str);
            if (rsp != NULL)
                freeReplyObject(rsp);
            return;
        }
    }

    if (rsp != NULL)
        freeReplyObject(rsp);
}

string Redis::GetKey(const string& cmd)
{
    // 多进程时，有可能没先调用 exec
    if (m_ctx == NULL)
    {
        instance()->Reconnect();
    }
    // 初始化成功 or 失败
    if (m_ctx == NULL)
    {
        ERR_LOG("No Available redis server.");
        return "";
    }

    string result;
    redisReply* rsp = (redisReply*)redisCommand(m_ctx,cmd.c_str());
    if (rsp != NULL)
    {
        if (rsp->type == REDIS_REPLY_STRING)
        {
            result = rsp->str;
        }
        else if(rsp->type == REDIS_REPLY_ERROR)
        {
            ERR_LOG("redis error:%s.",rsp->str);
        }
        freeReplyObject(rsp);
    }
    return result;
}


